
#include <stdio.h>

#include <libavutil/log.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h>
#include <SDL.h>

typedef struct _VideoState
{
    AVCodecContext* avctx;
    AVPacket*       pkt;
    AVFrame*        frame;
    SDL_Texture*    texture;
}VideoState;

static SDL_Window* win = NULL;
static SDL_Renderer* renderer =NULL;
static int w_width = 1280;
static int w_height = 720;

static void render(VideoState* is)
{
    SDL_UpdateYUVTexture(is->texture,NULL,
                         is->frame->data[0],is->frame->linesize[0],
                         is->frame->data[1],is->frame->linesize[1],
                         is->frame->data[2],is->frame->linesize[2]
                        );

    SDL_RenderClear(renderer);
    SDL_RenderCopy(renderer,is->texture,NULL,NULL);
    SDL_RenderPresent(renderer);
}

static int decode(VideoState* is)
{
    char buf[1024];
    int ret = -1;
    ret = avcodec_send_packet(is->avctx,is->pkt);
    if(ret < 0)
    {
        av_log(NULL,AV_LOG_ERROR,"failed to send frame to decoder");
        goto __OUT;
    }

    while(ret >= 0)
    {
        ret = avcodec_receive_frame(is->avctx,is->frame);
        if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
        {
            ret = 0;
            goto __OUT;
        }
        else if(ret < 0)
        {
            ret = -1;
            goto __OUT;
        }
        render(is);
    }
__OUT:
    return ret;
}

#undef main
int main()
{
    av_log_set_level(AV_LOG_DEBUG);
    // 1.输入参数
    const char* src = "D:/videos/try everything.mp4";
    int ret = -1;
    int index = -1;
    AVFormatContext* fmtCtx = NULL;
    AVStream* inStream = NULL;
    const AVCodec* codec = NULL;
    AVCodecContext* ctx = NULL;
    Uint32 pixformat = 0;
    VideoState* is = NULL;
    AVPacket *pkt = NULL;
    // 2.初始化SDL，创建窗口和Render
    SDL_Texture* texture = NULL;
    AVFrame*  frame = NULL;

    is = av_mallocz(sizeof(VideoState));
    if(!is)
    {
        av_log(NULL,AV_LOG_ERROR,"no memrory\n");
        goto __END;
    }

    if(SDL_Init(SDL_INIT_VIDEO))
    {
        fprintf(stderr,"Could not initialize SDL - %s\n",SDL_GetError());
        return -1;
    }

    win = SDL_CreateWindow("Simple Plyaer",
                           SDL_WINDOWPOS_UNDEFINED,
                           SDL_WINDOWPOS_UNDEFINED,
                           w_width,w_height,
                           SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);

    if(!win)
    {
        fprintf(stderr, "Failed to create window, %s\n",SDL_GetError());
        goto __END;
    }

    renderer = SDL_CreateRenderer(win,-1,0);


    // 3.打开多媒体文件，并获取流信息
    ret = avformat_open_input(&fmtCtx,src,NULL,NULL);

    if(ret < 0)
    {
        av_log(NULL,AV_LOG_ERROR,"%s\n",av_err2str(ret));
        goto __END;
    }

    ret = avformat_find_stream_info(fmtCtx,NULL);
    if(ret < 0)
    {
        av_log(NULL,AV_LOG_ERROR,"%s\n",av_err2str(ret));
        goto __END;
    }

    // 4.查找最好的视频流
    index = av_find_best_stream(fmtCtx,AVMEDIA_TYPE_VIDEO,-1,-1,NULL,0);
    if(index < 0)
    {
        av_log(fmtCtx,AV_LOG_ERROR,"does not include audio stream\n");
        goto __END;
    }

    // 5.根据流中的codec_id，获取编码器
    inStream = fmtCtx->streams[index];

    codec = avcodec_find_decoder(inStream->codecpar->codec_id);
    if(!codec)
    {
        av_log(NULL,AV_LOG_ERROR,"don't find codec \n");
        goto __END;
    }

    // 6.创建编码器上下文
    ctx = avcodec_alloc_context3(codec);
    if(!ctx)
    {
        av_log(NULL,AV_LOG_ERROR,"no memrory\n");
        goto __END;
    }

    // 7.从视频流中拷贝编解码参数到编码器上下文中
    ret = avcodec_parameters_to_context(ctx,inStream->codecpar);
    if(ret < 0)
    {
        goto __END;
    }

    // 8.绑定编码器上下文
    ret = avcodec_open2(ctx,codec,NULL);
    if(ret < 0)
    {
        av_log(ctx,AV_LOG_ERROR,"don't open codec : %s \n",av_err2str(ret));
        goto __END;
    }

    // 9.根据视频的宽/高创建纹理
    int video_width = ctx->width;
    int  video_height = ctx->height;
    pixformat = SDL_PIXELFORMAT_IYUV;
    texture = SDL_CreateTexture(renderer,
                                pixformat,
                                SDL_TEXTUREACCESS_STREAMING,
                                video_width,
                                video_height);
    pkt = av_packet_alloc();
    frame = av_frame_alloc();

    // 主要要赋值的变量都有效
    is->texture = texture;
    is->avctx = ctx;
    is->pkt = pkt;
    is->frame = frame;
    // 10.从多媒体文件中读取数据，进行解码

    SDL_Event event;
    while(av_read_frame(fmtCtx,pkt) >= 0)
    {
        if(pkt->stream_index == index)
        {
            // 11.对解码后的数据视频帧进行渲染
            decode(is);
        }

        // 12.处理SDL事件
        SDL_PollEvent(&event);

        switch (event.type) {
        case SDL_QUIT:
            goto __QUIT;
            break;
        default:
            break;
        }
        av_packet_unref(pkt);
    }

    // 清除缓冲区数据
    is->pkt =NULL;
    decode(is);

__QUIT:
    ret = 0;

__END:
    // 13.释放资源
    if(frame)
    {
        av_frame_free(&frame);
    }

    if(pkt){
        av_packet_free(&pkt);
    }

    if(fmtCtx)
    {
        avformat_close_input(&fmtCtx);
    }

    if(win)
    {
        SDL_DestroyWindow(win);
    }

    if(renderer)
    {
        SDL_DestroyRenderer(renderer);
    }

    if(texture)
    {
        SDL_DestroyTexture(texture);
    }
    SDL_Quit();

    return ret;
}


// DeepSeek 完成的！
/*
#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h>
#include <SDL.h>

typedef struct _VideoState
{
    AVCodecContext* avctx;
    AVPacket*       pkt;
    AVFrame*        frame;
    SDL_Texture*    texture;
    struct SwsContext* sws_ctx;
}VideoState;

static SDL_Window* win = NULL;
static SDL_Renderer* renderer =NULL;
static int w_width = 1280;
static int w_height = 720;

static void render(VideoState* is)
{
    if (!is->frame->data[0]) return;

    SDL_UpdateYUVTexture(is->texture, NULL,
                         is->frame->data[0], is->frame->linesize[0],
                         is->frame->data[1], is->frame->linesize[1],
                         is->frame->data[2], is->frame->linesize[2]);

    SDL_RenderClear(renderer);
    SDL_RenderCopy(renderer, is->texture, NULL, NULL);
    SDL_RenderPresent(renderer);
}

static int decode(VideoState* is)
{
    int ret = -1;

    if (!is->pkt->data) {
        return 0;
    }

    ret = avcodec_send_packet(is->avctx, is->pkt);
    if (ret < 0 && ret != AVERROR(EAGAIN)) {
        av_log(NULL, AV_LOG_ERROR, "failed to send packet to decoder: %s\n", av_err2str(ret));
        return ret;
    }

    while (ret >= 0) {
        ret = avcodec_receive_frame(is->avctx, is->frame);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            return 0;
        } else if (ret < 0) {
            av_log(NULL, AV_LOG_ERROR, "error during decoding: %s\n", av_err2str(ret));
            return ret;
        }

        // 成功解码一帧，进行渲染
        render(is);
        av_frame_unref(is->frame);
    }

    return 0;
}

#undef main
int main()
{
    av_log_set_level(AV_LOG_DEBUG);

    // 1.输入参数
    const char* src = "D:/videos/try everything.mp4";
    int ret = -1;
    int index = -1;
    AVFormatContext* fmtCtx = NULL;
    AVStream* inStream = NULL;
    const AVCodec* codec = NULL;
    AVCodecContext* ctx = NULL;
    Uint32 pixformat = 0;
    VideoState* is = NULL;
    AVPacket *pkt = NULL;
    SDL_Texture* texture = NULL;
    AVFrame* frame = NULL;

    // 初始化VideoState
    is = av_mallocz(sizeof(VideoState));
    if (!is) {
        av_log(NULL, AV_LOG_ERROR, "no memory\n");
        goto __END;
    }

    // 2.初始化SDL
    if (SDL_Init(SDL_INIT_VIDEO)) {
        fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
        goto __END;
    }

    win = SDL_CreateWindow("Simple Player",
                           SDL_WINDOWPOS_UNDEFINED,
                           SDL_WINDOWPOS_UNDEFINED,
                           w_width, w_height,
                           SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);

    if (!win) {
        fprintf(stderr, "Failed to create window, %s\n", SDL_GetError());
        goto __END;
    }

    renderer = SDL_CreateRenderer(win, -1, 0);
    if (!renderer) {
        fprintf(stderr, "Failed to create renderer, %s\n", SDL_GetError());
        goto __END;
    }

    // 3.打开多媒体文件
    ret = avformat_open_input(&fmtCtx, src, NULL, NULL);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot open input file: %s\n", av_err2str(ret));
        goto __END;
    }

    ret = avformat_find_stream_info(fmtCtx, NULL);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot find stream info: %s\n", av_err2str(ret));
        goto __END;
    }

    // 4.查找视频流
    index = av_find_best_stream(fmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    if (index < 0) {
        av_log(fmtCtx, AV_LOG_ERROR, "Cannot find video stream\n");
        goto __END;
    }

    inStream = fmtCtx->streams[index];

    // 5.获取解码器
    codec = avcodec_find_decoder(inStream->codecpar->codec_id);
    if (!codec) {
        av_log(NULL, AV_LOG_ERROR, "Failed to find codec\n");
        goto __END;
    }

    // 6.创建解码器上下文
    ctx = avcodec_alloc_context3(codec);
    if (!ctx) {
        av_log(NULL, AV_LOG_ERROR, "Failed to allocate codec context\n");
        goto __END;
    }

    // 7.拷贝参数
    ret = avcodec_parameters_to_context(ctx, inStream->codecpar);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Failed to copy codec parameters: %s\n", av_err2str(ret));
        goto __END;
    }

    // 8.打开解码器
    ret = avcodec_open2(ctx, codec, NULL);
    if (ret < 0) {
        av_log(ctx, AV_LOG_ERROR, "Failed to open codec: %s\n", av_err2str(ret));
        goto __END;
    }

    // 9.创建纹理
    int video_width = ctx->width;
    int video_height = ctx->height;

    // 根据像素格式选择合适的SDL纹理格式
    if (ctx->pix_fmt == AV_PIX_FMT_YUV420P) {
        pixformat = SDL_PIXELFORMAT_IYUV;
    } else {
        // 如果不是YUV420P，需要转换
        pixformat = SDL_PIXELFORMAT_IYUV;
    }

    texture = SDL_CreateTexture(renderer,
                                pixformat,
                                SDL_TEXTUREACCESS_STREAMING,
                                video_width,
                                video_height);
    if (!texture) {
        fprintf(stderr, "Failed to create texture: %s\n", SDL_GetError());
        goto __END;
    }

    // 10.分配packet和frame
    pkt = av_packet_alloc();
    if (!pkt) {
        av_log(NULL, AV_LOG_ERROR, "Failed to allocate packet\n");
        goto __END;
    }

    frame = av_frame_alloc();
    if (!frame) {
        av_log(NULL, AV_LOG_ERROR, "Failed to allocate frame\n");
        goto __END;
    }

    // 初始化VideoState
    is->avctx = ctx;
    is->pkt = pkt;
    is->frame = frame;
    is->texture = texture;
    is->sws_ctx = NULL;

    av_dump_format(fmtCtx, 0, src, 0);

    // 主循环
    SDL_Event event;
    int quit = 0;

    while (!quit && av_read_frame(fmtCtx, pkt) >= 0) {
        if (pkt->stream_index == index) {
            ret = decode(is);
            if (ret < 0) {
                break;
            }
        }
        av_packet_unref(pkt);

        // 处理SDL事件
        while (SDL_PollEvent(&event)) {
            switch (event.type) {
            case SDL_QUIT:
                quit = 1;
                break;
            case SDL_KEYDOWN:
                if (event.key.keysym.sym == SDLK_ESCAPE) {
                    quit = 1;
                }
                break;
            default:
                break;
            }
        }

        // 添加小延迟以减少CPU占用
        SDL_Delay(10);
    }

    // 刷新解码器
    pkt->data = NULL;
    pkt->size = 0;
    decode(is);

__END:
    // 13.释放资源
    if (frame) {
        av_frame_free(&frame);
    }

    if (pkt) {
        av_packet_free(&pkt);
    }

    if (ctx) {
        avcodec_free_context(&ctx);
    }

    if (fmtCtx) {
        avformat_close_input(&fmtCtx);
    }

    if (is) {
        if (is->sws_ctx) {
            sws_freeContext(is->sws_ctx);
        }
        av_free(is);
    }

    if (texture) {
        SDL_DestroyTexture(texture);
    }

    if (renderer) {
        SDL_DestroyRenderer(renderer);
    }

    if (win) {
        SDL_DestroyWindow(win);
    }

    SDL_Quit();

    return ret;
}
*/

/*
#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h>
#include <libavutil/time.h>
#include <SDL.h>

typedef struct _VideoState {
    AVFormatContext* fmt_ctx;
    AVCodecContext* video_avctx;
    int video_stream_index;
    AVPacket* pkt;
    AVFrame* frame;
    AVFrame* rgb_frame;
    SDL_Texture* texture;
    struct SwsContext* sws_ctx;

    // 播放控制
    int quit;
    int paused;

    // 同步信息
    double frame_timer;
    double frame_delay;
    double video_clock;

    // 统计信息
    int frame_count;
    Uint32 start_time;
} VideoState;

static SDL_Window* win = NULL;
static SDL_Renderer* renderer = NULL;
static int w_width = 1280;
static int w_height = 720;

// 获取当前时间（秒）
static double get_current_time() {
    return (double)SDL_GetTicks() / 1000.0;
}

// 计算帧延迟
static double get_frame_delay(VideoState* is) {
    double delay = av_q2d(is->fmt_ctx->streams[is->video_stream_index]->time_base);

    // 如果帧有持续时间，使用它
    if (is->frame->pkt_duration) {
        delay = is->frame->pkt_duration * av_q2d(is->fmt_ctx->streams[is->video_stream_index]->time_base);
    }
    // 否则使用帧率计算
    else {
        AVRational frame_rate = av_guess_frame_rate(is->fmt_ctx,
                                                    is->fmt_ctx->streams[is->video_stream_index],
                                                    NULL);
        if (frame_rate.num && frame_rate.den) {
            delay = 1.0 / av_q2d(frame_rate);
        }
    }

    return delay;
}

// 渲染帧
static void render_frame(VideoState* is) {
    if (!is->frame->data[0]) return;

    // 转换帧格式为RGB（如果需要）
    if (is->sws_ctx) {
        sws_scale(is->sws_ctx,
                  (const uint8_t* const*)is->frame->data,
                  is->frame->linesize,
                  0, is->video_avctx->height,
                  is->rgb_frame->data,
                  is->rgb_frame->linesize);

        SDL_UpdateTexture(is->texture, NULL,
                          is->rgb_frame->data[0],
                          is->rgb_frame->linesize[0]);
    } else {
        // 直接使用YUV格式
        SDL_UpdateYUVTexture(is->texture, NULL,
                             is->frame->data[0], is->frame->linesize[0],
                             is->frame->data[1], is->frame->linesize[1],
                             is->frame->data[2], is->frame->linesize[2]);
    }

    SDL_RenderClear(renderer);
    SDL_RenderCopy(renderer, is->texture, NULL, NULL);
    SDL_RenderPresent(renderer);

    // 更新统计信息
    is->frame_count++;
    if (is->frame_count == 1) {
        is->start_time = SDL_GetTicks();
    }
}

// 帧率控制
static void frame_rate_control(VideoState* is) {
    if (is->frame_count == 0) {
        is->frame_timer = get_current_time();
    }

    double actual_delay = get_frame_delay(is);
    double current_time = get_current_time();
    double delay = actual_delay;

    // 计算实际延迟与预期延迟的差异
    double diff = current_time - is->frame_timer;
    double sync_threshold = 0.01;

    if (fabs(diff) < actual_delay) {
        if (diff < actual_delay - sync_threshold) {
            delay = actual_delay - diff;
        } else if (diff > actual_delay + sync_threshold) {
            delay = 0;
        } else {
            delay = actual_delay;
        }
    }

    // 限制最大和最小延迟
    if (delay > 0.1) delay = 0.1;
    if (delay < 0) delay = 0;

    // 等待适当的时间
    if (delay > 0) {
        SDL_Delay((Uint32)(delay * 1000));
    }

    is->frame_timer += actual_delay;
}

// 解码视频帧
static int decode_video_frame(VideoState* is) {
    int ret = 0;

    // 发送packet到解码器
    ret = avcodec_send_packet(is->video_avctx, is->pkt);
    if (ret < 0 && ret != AVERROR(EAGAIN)) {
        av_log(NULL, AV_LOG_WARNING, "Error sending packet: %s\n", av_err2str(ret));
        return ret;
    }

    // 尝试接收帧
    while (ret >= 0) {
        ret = avcodec_receive_frame(is->video_avctx, is->frame);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            return 0;
        } else if (ret < 0) {
            av_log(NULL, AV_LOG_WARNING, "Error receiving frame: %s\n", av_err2str(ret));
            return ret;
        }

        // 成功解码一帧
        if (!is->paused) {
            render_frame(is);
            frame_rate_control(is);
        }

        av_frame_unref(is->frame);
    }

    return 0;
}

// 处理SDL事件
static void handle_events(VideoState* is) {
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
        switch (event.type) {
        case SDL_QUIT:
            is->quit = 1;
            break;
        case SDL_KEYDOWN:
            switch (event.key.keysym.sym) {
            case SDLK_ESCAPE:
            case SDLK_q:
                is->quit = 1;
                break;
            case SDLK_SPACE:
                is->paused = !is->paused;
                printf(is->paused ? "Paused\n" : "Resumed\n");
                break;
            case SDLK_f:
                // 切换全屏
                SDL_SetWindowFullscreen(win,
                                        SDL_GetWindowFlags(win) ^ SDL_WINDOW_FULLSCREEN_DESKTOP);
                break;
            }
            break;
        case SDL_WINDOWEVENT:
            if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
                w_width = event.window.data1;
                w_height = event.window.data2;
            }
            break;
        }
    }
}

// 初始化视频状态
static VideoState* init_video_state() {
    VideoState* is = av_mallocz(sizeof(VideoState));
    if (!is) return NULL;

    is->pkt = av_packet_alloc();
    is->frame = av_frame_alloc();
    is->rgb_frame = av_frame_alloc();

    if (!is->pkt || !is->frame || !is->rgb_frame) {
        av_log(NULL, AV_LOG_ERROR, "Failed to allocate packets/frames\n");
        return NULL;
    }

    is->quit = 0;
    is->paused = 0;
    is->frame_timer = 0;
    is->frame_delay = 0;
    is->video_clock = 0;
    is->frame_count = 0;

    return is;
}

// 清理资源
static void cleanup(VideoState* is, AVFormatContext* fmt_ctx, AVCodecContext* codec_ctx) {
    if (is) {
        if (is->pkt) av_packet_free(&is->pkt);
        if (is->frame) av_frame_free(&is->frame);
        if (is->rgb_frame) av_frame_free(&is->rgb_frame);
        if (is->texture) SDL_DestroyTexture(is->texture);
        if (is->sws_ctx) sws_freeContext(is->sws_ctx);
        av_free(is);
    }

    if (codec_ctx) avcodec_free_context(&codec_ctx);
    if (fmt_ctx) avformat_close_input(&fmt_ctx);
    if (renderer) SDL_DestroyRenderer(renderer);
    if (win) SDL_DestroyWindow(win);
    SDL_Quit();
}

#undef main
int main(int argc, char* argv[]) {
    av_log_set_level(AV_LOG_INFO);

    const char* src = "D:/videos/try everything.mp4";
    if (argc > 1) {
        src = argv[1];
    }

    int ret = -1;
    AVFormatContext* fmt_ctx = NULL;
    AVCodecContext* codec_ctx = NULL;
    const AVCodec* codec = NULL;
    VideoState* is = NULL;

    // 初始化VideoState
    is = init_video_state();
    if (!is) {
        goto __END;
    }

    // 初始化SDL
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER)) {
        fprintf(stderr, "Could not initialize SDL: %s\n", SDL_GetError());
        goto __END;
    }

    win = SDL_CreateWindow("FFmpeg SDL2 Player - Press SPACE to pause, F for fullscreen, ESC to quit",
                           SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                           w_width, w_height,
                           SDL_WINDOW_RESIZABLE);
    if (!win) {
        fprintf(stderr, "Failed to create window: %s\n", SDL_GetError());
        goto __END;
    }

    renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    if (!renderer) {
        fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError());
        goto __END;
    }

    // 打开输入文件
    ret = avformat_open_input(&fmt_ctx, src, NULL, NULL);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot open input file: %s\n", av_err2str(ret));
        goto __END;
    }

    ret = avformat_find_stream_info(fmt_ctx, NULL);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot find stream info: %s\n", av_err2str(ret));
        goto __END;
    }

    // 查找视频流
    is->video_stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    if (is->video_stream_index < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot find video stream\n");
        goto __END;
    }

    // 获取解码器
    codec = avcodec_find_decoder(fmt_ctx->streams[is->video_stream_index]->codecpar->codec_id);
    if (!codec) {
        av_log(NULL, AV_LOG_ERROR, "Unsupported codec\n");
        goto __END;
    }

    codec_ctx = avcodec_alloc_context3(codec);
    if (!codec_ctx) {
        av_log(NULL, AV_LOG_ERROR, "Failed to allocate codec context\n");
        goto __END;
    }

    ret = avcodec_parameters_to_context(codec_ctx, fmt_ctx->streams[is->video_stream_index]->codecpar);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Failed to copy codec parameters\n");
        goto __END;
    }

    ret = avcodec_open2(codec_ctx, codec, NULL);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Failed to open codec: %s\n", av_err2str(ret));
        goto __END;
    }

    // 创建纹理
    int video_width = codec_ctx->width;
    int video_height = codec_ctx->height;

    // 根据像素格式选择纹理格式
    Uint32 sdl_pixel_format;
    if (codec_ctx->pix_fmt == AV_PIX_FMT_YUV420P) {
        sdl_pixel_format = SDL_PIXELFORMAT_IYUV;
        is->sws_ctx = NULL;  // 不需要转换
    } else {
        // 需要格式转换
        sdl_pixel_format = SDL_PIXELFORMAT_RGB24;
        is->sws_ctx = sws_getContext(video_width, video_height, codec_ctx->pix_fmt,
                                     video_width, video_height, AV_PIX_FMT_RGB24,
                                     SWS_BILINEAR, NULL, NULL, NULL);

        // 分配RGB帧
        is->rgb_frame->format = AV_PIX_FMT_RGB24;
        is->rgb_frame->width = video_width;
        is->rgb_frame->height = video_height;
        ret = av_frame_get_buffer(is->rgb_frame, 32);
        if (ret < 0) {
            av_log(NULL, AV_LOG_ERROR, "Failed to allocate RGB frame\n");
            goto __END;
        }
    }

    is->texture = SDL_CreateTexture(renderer, sdl_pixel_format,
                                    SDL_TEXTUREACCESS_STREAMING,
                                    video_width, video_height);
    if (!is->texture) {
        fprintf(stderr, "Failed to create texture: %s\n", SDL_GetError());
        goto __END;
    }

    is->fmt_ctx = fmt_ctx;
    is->video_avctx = codec_ctx;

    // 显示文件信息
    av_dump_format(fmt_ctx, 0, src, 0);
    printf("\nControls:\n");
    printf("SPACE - Pause/Resume\n");
    printf("F - Toggle fullscreen\n");
    printf("ESC or Q - Quit\n\n");

    // 主播放循环
    while (!is->quit) {
        handle_events(is);

        if (is->paused) {
            SDL_Delay(10);
            continue;
        }

        ret = av_read_frame(fmt_ctx, is->pkt);
        if (ret < 0) {
            // 文件结束或错误
            if (ret == AVERROR_EOF) {
                printf("End of file reached\n");
            } else {
                av_log(NULL, AV_LOG_ERROR, "Error reading frame: %s\n", av_err2str(ret));
            }
            break;
        }

        if (is->pkt->stream_index == is->video_stream_index) {
            decode_video_frame(is);
        }

        av_packet_unref(is->pkt);
    }

    // 刷新解码器
    is->pkt->data = NULL;
    is->pkt->size = 0;
    decode_video_frame(is);

    // 显示统计信息
    Uint32 end_time = SDL_GetTicks();
    if (is->frame_count > 0 && end_time > is->start_time) {
        double elapsed = (end_time - is->start_time) / 1000.0;
        double fps = is->frame_count / elapsed;
        printf("Playback statistics:\n");
        printf("Frames decoded: %d\n", is->frame_count);
        printf("Playback time: %.2f seconds\n", elapsed);
        printf("Average FPS: %.2f\n", fps);
    }

    ret = 0;

__END:
    cleanup(is, fmt_ctx, codec_ctx);
    return ret;
}

*/
